package com.example.md.controller;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.regex.Pattern;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.example.md.common.Result;
import com.example.md.dto.file.DeleteFileReqDTO;
import com.example.md.dto.file.DeleteFolderReqDTO;
import com.example.md.dto.file.FileTreeResDTO;
import com.example.md.dto.file.NewFileReqDTO;
import com.example.md.dto.file.NewFolderReqDTO;
import com.example.md.dto.file.RenameFileReqDTO;
import com.example.md.dto.file.RenameFolderReqDTO;
import com.example.md.dto.user.LoginStatus;
import com.example.md.dto.file.FileTreeResDTO.TreeNode;
import com.example.md.service.FileService;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.PostMapping;


@RestController
@RequestMapping("/file")
public class FileController {

    @Autowired
    private FileService fileService;

    @GetMapping("/markdown/image")
    public void downloadMarkdownImage(@RequestParam("path") String path, HttpServletResponse response) throws IOException {
        String extension = path.substring(path.lastIndexOf(".") + 1);
        String[] exts = new String[] {"png", "jpg", "gif"};
        if (!ArrayUtil.contains(exts, extension.toLowerCase())) {
            return;
        }

        String filePath = StrUtil.builder().append(markdownDir).append(File.separator).append(path).toString();

        File file = new File(filePath);
        if (!file.exists()) return;

        ServletOutputStream outputStream = response.getOutputStream();
        response.setHeader("Content-Disposition", "attachment;filename=aaa");
        response.setContentType("application/octet-stream");
        outputStream.write(FileUtil.readBytes(file));
        outputStream.flush();
        outputStream.close();
    }

    
    @Autowired
    private LoginStatus loginStatus;

    @GetMapping("/markdown/export")
    public void exportMarkdown(@RequestParam("token") String token, HttpServletResponse response) throws Exception {
        if (!loginStatus.getTokens().contains(token)) {
            throw new RuntimeException("token 不存在或已过期");
        }

        String filename = markdownDir.substring(markdownDir.lastIndexOf("/") + 1) + ".zip";
        System.out.println("filename: " + filename);
        String zipFilePath = markdownDir.substring(0, markdownDir.lastIndexOf("/")) + File.separator + filename;
        System.out.println("zipFilePath: " + zipFilePath);
        
        File zipFile = new File(zipFilePath);
        if (zipFile.exists()) {
            zipFile.delete();
        }
        fileService.zipFolder(markdownDir, zipFilePath );

        zipFile = new File(zipFilePath);
        if (!zipFile.exists()) {
            throw new RuntimeException("压缩文件不存在​");
        }

        ServletOutputStream outputStream = response.getOutputStream();
        response.setHeader("Content-Disposition", "attachment;filename=" + filename);
        response.setContentType("application/octet-stream");
        outputStream.write(FileUtil.readBytes(zipFile));
        outputStream.flush();
        outputStream.close();
    }

    
    @Value("${md_dir}")
    public String markdownDir;

    /**
     * 获取文件树
     * @return
     */
    @GetMapping("/tree")
    public Result<FileTreeResDTO> getFileTree() throws IOException {
        System.out.println("markdown-root-dir: " + markdownDir);
        TreeNode tree = fileService.createTree(markdownDir, ".");
        FileTreeResDTO result = FileTreeResDTO.builder().tree(tree).build();
        return Result.success(result);
    }

    /**
     * 删除文件
     * @param requestBody
     */
    @PostMapping("/delete")
    public Result<Boolean> deleteFile(@RequestBody @Validated DeleteFileReqDTO requestBody) throws Exception {
        String path = requestBody.getPath();
        Path fullPath = fileService.validatePath(path);
        if (!Files.isRegularFile(fullPath)) {
            return Result.failed("Path is not a file");
        }
        Files.delete(fullPath);
        return Result.success(true);
    }


    private static final Pattern INVALID_FILENAME_PATTERN = Pattern.compile("[\\\\/:*?\"<>|]");

    /**
     * 重命名文件
     */
    @PostMapping("/rename")
    public Result<Boolean> renameFile(@RequestBody @Validated RenameFileReqDTO requestBody) throws Exception {
        // 验证新名称
        if (requestBody.getNewName() == null || INVALID_FILENAME_PATTERN.matcher(requestBody.getNewName()).find()) 
        {
            return Result.failed("Invalid file name");
        }

        Path oldFullPath = fileService.validatePath(requestBody.getPath());
        Path oldDir = oldFullPath.getParent();
        Path newPath = oldDir.resolve(requestBody.getNewName());

        // 检查原路径是否存在
        if (!Files.isRegularFile(oldFullPath)) {
            return Result.failed("Path is not a file");
        }

        // 检查新名称是否已存在
        if (Files.exists(newPath)) {
            return Result.failed("File with the same name already exists");
        }

        // 重命名文件
        Files.move(oldFullPath, newPath, StandardCopyOption.REPLACE_EXISTING);

        return Result.success(true);
    }


    /**
     * 删除文件夹
     * @param requestBody
     * @return
     * @throws Exception
     */
    @PostMapping("/folder/delete")
    public Result<Boolean> deleteFolder(@RequestBody @Validated DeleteFolderReqDTO requestBody) throws Exception {
        // 验证路径
        if (StrUtil.isBlank(requestBody.getPath())) {
            return Result.failed("Path is required");
        }

        Path fullPath = fileService.validatePath(requestBody.getPath());

        // 检查路径是否存在且为目录
        if (!FileUtil.exist(fullPath.toFile())) {
            return Result.failed("Folder not found");
        }
        if (!FileUtil.isDirectory(fullPath.toFile())) {
            return Result.failed("Path is not a directory");
        }

        // 使用Hutool递归删除文件夹
        FileUtil.del(fullPath.toFile());

        return Result.success(true);
    }
    

    /**
     * 重命名文件夹
     * @param requestBody
     * @return
     * @throws Exception
     */
    @PostMapping("/folder/rename")
    public Result<Boolean> renameFolder(@RequestParam @Validated RenameFolderReqDTO requestBody) throws Exception {
        // 验证输入
        if (StrUtil.isBlank(requestBody.getNewName()) || INVALID_FILENAME_PATTERN.matcher(requestBody.getNewName()).find()) 
        {
            return Result.failed("Invalid folder name");
        }

        Path oldFullPath = fileService.validatePath(requestBody.getPath());
        Path parentDir = oldFullPath.getParent();
        Path newPath = parentDir.resolve(requestBody.getNewName());

        // 检查原文件夹是否存在
        File oldFolder = oldFullPath.toFile();
        if (!oldFolder.exists()) {
            return Result.failed("Folder not found");
        }
        if (!oldFolder.isDirectory()) {
            return Result.failed("Path is not a directory");
        }

        // 检查新名称是否已存在
        File newFolder = newPath.toFile();
        if (newFolder.exists()) {
            return Result.failed("Folder with the same name already exists");
        }

        // 使用Hutool重命名文件夹
        FileUtil.rename(oldFolder, requestBody.getNewName(), false, true);

        return Result.success(true);
    }

    /**
     * 创建文件
     * @param requestBody
     * @return
     * @throws Exception
     */
    @PostMapping("/new")
    public Result<Boolean> newFile(@RequestBody @Validated NewFileReqDTO requestBody) throws Exception {
         // 验证文件名
        if (StrUtil.isBlank(requestBody.getName()) || INVALID_FILENAME_PATTERN.matcher(requestBody.getName()).find()) 
        {
            return Result.failed("Invalid file name");
        }

        Path parentFullPath = fileService.validatePath(requestBody.getParentPath());
        Path newFilePath = parentFullPath.resolve(requestBody.getName());

        // 检查文件是否已存在
        if (Files.exists(newFilePath)) {
            return Result.failed("File already exists");
        }

        // 确保父目录存在
        if (!Files.exists(parentFullPath)) {
            Files.createDirectories(parentFullPath);
        }

        // 创建新文件
        FileUtil.touch(newFilePath.toFile());
        
        return Result.success(true);
    }


    /**
     * 创建文件夹
     */
    @PostMapping("/folder/new")
    public Result<Boolean> newFolder(@RequestBody @Validated NewFolderReqDTO requestBody) throws Exception {
        // 验证文件夹名称
        if (StrUtil.isBlank(requestBody.getName()) || INVALID_FILENAME_PATTERN.matcher(requestBody.getName()).find()) 
        {
            return Result.failed("Invalid folder name");
        }

        Path parentFullPath = fileService.validatePath(requestBody.getParentPath());
        File newFolder = new File(parentFullPath.toFile(), requestBody.getName());

        // 检查文件夹是否已存在
        if (newFolder.exists()) {
            return Result.failed("Folder already exists");
        }

        // 创建新文件夹
        File created = FileUtil.mkdir(newFolder);
        if (created == null) {
            return Result.failed("Failed to create folder (unknown reason)");
        }

        return Result.success(true);
    }
    
}

